using System;
using System.Reflection;
using DMS.BEs;
using DMS.DTOs;
using NHibernate;

namespace DMS.Mappers.Reload
{
    public class MapperDTOtoBE : IMapperDTOtoBE
    {
    	private readonly ISessionFactory sessionFactory;

    	public MapperDTOtoBE(ISessionFactory sessionFactory)
    	{
    		this.sessionFactory = sessionFactory;
    	}

    	public TB Map<TD, TB>(TD dto)
            where TD : IDTO
			where TB : IPersistent, new()
		{
			if (Equals(dto, default(TD)))
				throw new ArgumentNullException("dto");

			ISession session = sessionFactory.GetCurrentSession();

			TB be = session.Get<TB>(dto.Id);
			if (Equals(be, default(TB)))
			{
				if (!Equals(dto.Id, 0))
					throw new Exception(string.Format("Entity [{0}:{1}] not found", typeof(TB).FullName, dto.Id));
				be = new TB();
			}

			Type typeBE = be.GetType();
			Type typeDTO = dto.GetType();

			foreach (PropertyInfo propertyBE in typeBE.GetProperties())
			{
				if (propertyBE.Name.Equals("Id")) continue;

				string propertyName = typeof (IPersistent).IsAssignableFrom(propertyBE.PropertyType)
				                      	? propertyBE.Name + "Id"
				                      	: propertyBE.Name;

				PropertyInfo propertyDTO = typeDTO.GetProperty(propertyName);
				if (propertyDTO == null) continue;
				
				if (propertyDTO.PropertyType.Equals(propertyBE.PropertyType))
				{
					object value = propertyDTO.GetValue(dto, null);
					propertyBE.SetValue(be, value, null);
				}
				else if(typeof(IPersistent).IsAssignableFrom(propertyBE.PropertyType))
				{
					object id = propertyDTO.GetValue(dto, null);
					object entity = session.Get(propertyBE.PropertyType, id);
					propertyBE.SetValue(be, entity, null);
				}
			}

			return be;
		}
    }
}